package main

import (
	"crypto/sha1"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"time"

	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
)

const hostsDIR = `C:\Windows\System32\drivers\etc\hosts`
const hostsURL = `https://raw.githubusercontent.com/googlehosts/hosts/master/hosts-files/hosts`

var resText []byte
var oldHash string
var infoBar *walk.Label
var localVersion, remoteVersion *walk.LineEdit
var progressBar *walk.ProgressBar

func getDate(b []byte) string {
	reg := regexp.MustCompile(`Last updated: ([0-9\-]+)`)
	if reg.Match(b) {
		datab := reg.FindSubmatch(b)[1]
		return string(datab)
	}
	return ``
}

func getGitSha1(b []byte) string {
	tmp := []byte(fmt.Sprintf("blob %d\x00%s", len(b), b))
	return fmt.Sprintf(`%x`, sha1.Sum(tmp))
}

func getLocalInfo() {
	b, _ := ioutil.ReadFile(hostsDIR)
	date := getDate(b)
	if date != `` {
		oldHash = getGitSha1(b)
		localVersion.SetText(fmt.Sprintf("%s %s\n", date, oldHash[:7]))
	} else {
		localVersion.SetText(`未知`)
	}
}

func getRemoteInfoThread() {
	client := &http.Client{}
	req, _ := http.NewRequest("GET", hostsURL, nil)
	if oldHash == `` {
		getLocalInfo()
	}
	req.Header.Add("If-None-Match", fmt.Sprintf(`"%s"`, oldHash))
	res, _ := client.Do(req)
	if res.StatusCode == 200 {
		resText, _ = ioutil.ReadAll(res.Body)
		tmpHash := res.Header["Etag"][0]
		resHash := tmpHash[1 : len(tmpHash)-1]
		remoteVersion.SetText(fmt.Sprintf("%s %s\n", getDate(resText), resHash[:7]))
		infoBar.SetText(`需要更新，请点更新按钮更新`)
	} else if res.StatusCode == 304 {
		remoteVersion.SetText(localVersion.Text())
		infoBar.SetText(`已是最新版，无需更新`)
	} else {
		infoBar.SetText(fmt.Sprintf("请求失败，错误码%s\n", res.Status))
	}
	progressBar.SetMarqueeMode(false)
}

func getRemoteInfo() {
	infoBar.SetText(`正在获取最新版...`)
	progressBar.SetMarqueeMode(true)
	go getRemoteInfoThread()
}

func modifyFile() {
	if resText == nil {
		getLocalInfo()
		getRemoteInfo()
	}
	if resText != nil {
		ioutil.WriteFile(hostsDIR, resText, 0644)
		infoBar.SetText(`已更新至最新版`)
	}
}

func main() {
	time.AfterFunc(time.Second, getLocalInfo)
	icon, _ := walk.NewIconFromResourceId(15)
	Dialog{
		Title:     "GetHosts",
		Layout:    Grid{Columns: 3},
		MinSize:   Size{Width: 350, Height: 150},
		FixedSize: true,
		Icon:      icon,
		Font: Font{
			Family:    "Microsoft Yahei",
			PointSize: 9,
		},
		Children: []Widget{
			Label{Text: "本地版本："},
			LineEdit{ReadOnly: true, AssignTo: &localVersion},
			PushButton{Text: "刷新", OnClicked: getLocalInfo},
			Label{Text: "远程版本："},
			LineEdit{ReadOnly: true, AssignTo: &remoteVersion},
			PushButton{Text: "刷新", OnClicked: getRemoteInfo},
			ProgressBar{ColumnSpan: 3, AssignTo: &progressBar, MarqueeMode: false},
			Label{ColumnSpan: 2, AssignTo: &infoBar, Text: `GetHosts-1.0.3-20170626`},
			PushButton{Text: "更新", OnClicked: modifyFile},
		},
	}.Run(nil)
}
